package com.avicsafety.ezsystem.local_stoage;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.avicsafety.ezsystem.utils.DateTime;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.reactivex.annotations.NonNull;

/**
 * Description:本地存储类
 * Create by shili at 2018/8/1-13:18
 */
public class LocalStorage {

    private static final String TAG = "LocalStorage";

    private static Context mContext;

    private static SQLiteDatabase db;

    private static final String TABLE_NAME = "AVIC_COMMON_TABLE";
    private static final String SUB_TABLE_NAME = "AVIC_SUB_TABLE";

    private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();


    /**   ----------------------  基础部分  ---------------------- **/

    /**表结构*/
    public static final String CREATE_TABLE ="create table "+ TABLE_NAME +" ("
            +"id text,"
            +"name text,"
            +"data text,"
            +"sort1 text,"
            +"sort2 text,"
            +"sort3 text,"
            +"PRIMARY KEY (id,name)"
            +")";

    /**条件表结构*/
    public static final String CREATE_SUB_TABLE ="create table "+ SUB_TABLE_NAME +" ("
            +"id text,"
            +"name text,"
            +"value text,"
            +"pid text,"
            +"pname text,"
            +"PRIMARY KEY (id)"
            +")";

    /**
     * 内部类 用来创建数据库
     */
    private static void openDataBase(){
        if(mContext==null){
            SQLiteConstraintException e = new SQLiteConstraintException("上下文缺失,必须要在MyApplication中使用INIT进行初始化");
            throw e;
        }else{
            db = new DatabaseHelper(mContext,"mydb",null,1001).getWritableDatabase();
            Log.e("LocalStoage","get database object success!");
        }
    }

    /**
     * 内部类 判断表是否存在
     * @return
     */
    private static boolean tableIsExist(){
        String sql = "SELECT COUNT(*) " +
                "FROM sqlite_master " +
                "where type='table' " +
                "and name='"+ TABLE_NAME +"'";
        Cursor cursor = db.rawQuery(sql, null);
        cursor.moveToFirst();
        long count = cursor.getLong(0);
        cursor.close();
        Log.e(TAG,sql);
        return count>0?true:false;

    }

    /**
     * 内部类 用来创建一个表
     */
    private static void createTable(){
        db.beginTransaction();
        db.execSQL(CREATE_TABLE);
        db.execSQL(CREATE_SUB_TABLE);
        db.setTransactionSuccessful();
        db.endTransaction();
        Log.e(TAG,CREATE_TABLE);
        Log.e(TAG,CREATE_SUB_TABLE);
    }

    /**
     * 内部类 操作表前 判断是否具备所有条件
     */
    private static void check(){
        openDataBase();
        if(!tableIsExist()){
            createTable();
        }
    }

    /**
     * 初始化上下文
     * @param context
     */
    public static void init(Context context){
        mContext = context;
    }

    /**
     * 通过主键 判断是否存在
     * @param id
     * @param name
     * @return
     */
    public static boolean isExist(String id, String name){
        if(StringUtils.isEmpty(id)||StringUtils.isEmpty(name)){
            SQLiteConstraintException e = new SQLiteConstraintException("数据缺少主键信息 必须包含 id and name");
            throw e;
        }

        String sql = "SELECT COUNT(*) " +
                "FROM " + TABLE_NAME + " " +
                "WHERE id = '"+ id +"' " +
                "AND name='"+ name +"'";
        Cursor cursor = db.rawQuery(sql, null);
        cursor.moveToFirst();
        long count = cursor.getLong(0);
        cursor.close();
        Log.e(TAG,sql);
        return count>0?true:false;
    }



    /**  ---------------------- 数据插入和更新 -----------------------  **/

    /**
     * 插入或更新一个JAVA对象
     * 该方法为最简单的方式 没有条件 没有排序
     * @param name 表名
     * @param keyname 主键名 默认值 guid
     * @param t JAVA对象
     */
    public static <T> void pushModel(String name,String keyname, T t) {
        pushModel(name,keyname, t,null,null);
    }

    /**
     * 插入或更新一个JAVA对象
     * 该方法可以包含条件和排序 条件无限制 排序最多三个
     * @param name 表名
     * @param keyname 主键名 默认值 guid
     * @param t JAVA对象
     * @param con_keys 搜索条件的key 不是值
     * @param sorts 排序对象的值
     */
    public static <T> void pushModel(String name,String keyname, T t, String[] con_keys, String[] sorts) {
        try {
            push(name,keyname,new JSONObject(gson.toJson(t)), con_keys, sorts, true);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    /**
     * 插入JAVA集合
     * 最简单的方式 不包含条件筛选和排序
     * @param name 表名
     * @param keyname 主键名
     * @param list JAVA对象列表
     */
    public static void pushModelAll(String name,String keyname, List list) {
        pushModelAll(name,keyname,list,null,null);
    }

    /**
     * 插入一个JAVA集合
     * 包含排序和条件
     * @param name 表名
     * @param keyname 主键key 名称 通常为guid
     * @param list java对象数据
     * @param con_keys 条件素组
     * @param sorts 排序素组
     */
    public static void pushModelAll(String name, String keyname, List list, String[] con_keys, String[] sorts) {
        JSONArray array = null;
        try {
            array = new JSONArray(gson.toJson(list));
            pushAll(name, keyname, array, con_keys, sorts);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 插入JSONARRAY
     * @param name 表名
     * @param keyname 主键key 通常为guid
     * @param array json数组
     * @param con_keys 条件数组key
     * @param sorts 排序
     */
    public static void pushAll(String name, String keyname, JSONArray array, String[] con_keys, String[] sorts) {
        check(); //push前统一进行了验证
        for(int i=0; i<array.length();i++){
            try {
                JSONObject data = array.getJSONObject(i);
                push(name,keyname,data, con_keys,sorts, false);
            } catch (JSONException e) {
                e.printStackTrace();
            }

        }

    }

    /**
     * 插入或更新一个JSON对象
     * 不包含条件和排序
     * @param name 表名
     * @param keyname 主键名 默认值 guid
     * @param data json数据
     */
    public static void push(String name,String keyname, JSONObject data) {
        push(name,keyname, data, null, null, true);
    }

    /**
     * 插入或更新一个JSON对象
     * @param name 表名
     * @param keyname 主键名 默认值 guid
     * @param con_keys 条件key数组不是值 例如  String[] s = {"id","name"};
     * @param sorts 排序值的数组 不是key
     * @param data json数据
     */
    public static void push(String name, String keyname, JSONObject data, String[] con_keys, String[] sorts, Boolean needCheck) {
        if(StringUtils.isEmpty(keyname)){
            keyname = "guid";
        }
        if(data.has(keyname)&&!data.isNull(keyname)){
            try {
                //获取ID值 关键
                String id = data.has(keyname)&&!data.isNull(keyname)?data.getString(keyname):"";
                //将key数组 拼接成条件数组 关键
                if(con_keys==null||con_keys.length==0){
                    LocalData localData = new LocalData(name,id,data.toString(),sorts);
                    push(localData, null, needCheck);
                }
                else{
                    String[][] conditions = new String[con_keys.length][2];
                    for(int i=0;i<con_keys.length;i++){
                        conditions[i][0] = con_keys[i];
                        conditions[i][1] = getString(data, con_keys[i]);
                    }
                    LocalData localData = new LocalData(name,id,data.toString(),sorts);
                    push(localData, conditions, needCheck);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }


    private static String getString(JSONObject data,String keyname){
        if(data.has(keyname)&&!data.isNull(keyname)){
            try {
                return data.getString(keyname);
            } catch (JSONException e) {
                e.printStackTrace();
                return "";
            }
        }else{
            return "";
        }
    }

    /**
     * 如果有重复 就更新 没有就插入 外部不允许访问 私有
     * @param data 数据
     * @param conditions 条件
     * @param needCheck 是否需要验证
     */
    private static void push(LocalData data, String[][] conditions, boolean needCheck) {
        if(needCheck){
            check();
        }
        if(isExist(data.getId(),data.getName())){
            update(data,conditions);
        }else{
            insert(data,conditions);
        }

    }

    /**更新操作**/
    private static void update(LocalData data, String[][] conditions) {
        ContentValues values = new ContentValues() ;
        values.put("data", data.getData());
        values.put("sort1", data.getSort1());
        values.put("sort2", data.getSort2());
        values.put("sort3", data.getSort3());

        db.beginTransaction();
        db.update(TABLE_NAME,values,"id=? and name=?",new String[]{data.getId(),data.getName()});

        if(conditions!=null){
            db.delete(SUB_TABLE_NAME,"pid=?",new String[]{data.getId()});
            for(String[] arr : conditions){
                String name = arr[0];
                String value = arr[1];
                ContentValues rows = new ContentValues();
                rows.put("id",new Date().getTime()+"");
                rows.put("name", name);
                rows.put("value", value);
                rows.put("pid", data.getId());
                rows.put("pname", data.getName());
                db.insert(SUB_TABLE_NAME,null, rows);
            }
        }
        db.setTransactionSuccessful();
        db.endTransaction();


    }

    private static void insert(LocalData data, String[][] conditions) {
        ContentValues values = new ContentValues() ;
        values.put("id", data.getId());
        values.put("name", data.getName());
        values.put("data", data.getData());
        values.put("sort1", data.getSort1());
        values.put("sort2", data.getSort2());
        values.put("sort3", data.getSort3());

        db.beginTransaction();
        db.insert(TABLE_NAME,null, values);
        if(conditions!=null){
            for(String[] arr : conditions){
                String name = arr[0];
                String value = arr[1];
                ContentValues rows = new ContentValues() ;
                rows.put("id",new Date().getTime()+"");
                rows.put("name", name);
                rows.put("value", value);
                rows.put("pid", data.getId());
                rows.put("pname", data.getName());
                db.insert(SUB_TABLE_NAME,null, rows);
            }
        }
        db.setTransactionSuccessful();
        db.endTransaction();
    }




    /**  ---------------------- 读取简单对象 -----------------------  **/

    /**
     * 获取一个JAVA bean
     * @param id 编号
     * @param name 表名
     * @param <T> 类型
     * @return 该类型的model
     */
    public static <T> T findModel(String id, String name, Class<T> clazz){
        LocalData data = findOne(id, name);
        T t = gson.fromJson(data.getData(), clazz);
        return t;
    }

    /**
     * 获取一个JSON 的字符串
     * @param id 编号
     * @param name 表名
     */
    public static String find(String id, String name){
        LocalData data = findOne(id, name);
        return data.getData();
    }

    /**
     * 不对外开放了
     * @param id 主键
     * @param name 对应的服务器表名
     */
    private static LocalData findOne(String id, String name){
        check();
        LocalData data = new LocalData();
        Cursor cursor = db.query(TABLE_NAME, new String[]{"id","name","data","sort1","sort2","sort3"}, "id=? and name=?", new String[]{id,name},null,null,null);
        if(cursor==null){
            return null;
        }else{
            if (cursor.moveToNext()){
                data = cursor2model(cursor);
            }else{
                return null;
            }
        }
        return data;
    }

    /**
     * 通过表名获取JAVA对象列表
     * 很简单的方式 没有排序和查询
     * @param name 对应的服务器表名
     * @param clazz 数据类型
     */
    public static <T> List<T> findAll(String name, Class<T> clazz){
        return findAll(name,clazz,null,null,null,null);
    }

    /**
     * 通过表名获取数据列表
     * 很简单的方式 没有排序和查询
     * 不对外开放LocalData对象了
     * @param name 对应的服务器表名
     * @param conditions 条件 二维数组 例如: String where = {{"companyname":"企业名"},{"companyid","1"}}  字符串型
     * @param sorts 排序 例如: sor1 desc, sort2, sort3 desc
     * @param pagesize 分页
     * @param pageindex 当前页
     */
    public static <T> List<T> findAll(String name, Class<T> clazz, String[][] conditions, String sorts, Integer pagesize, Integer pageindex){
        List<LocalData> list = findAll(name,conditions,sorts,pagesize,pageindex);
        List<T> _list = new ArrayList<>();
        for(LocalData data:list){
            T t = gson.fromJson(data.getData(), clazz);
            _list.add(t);
        }
        return _list;
    }

    /**
     * 通过表名获取数据列表
     * 很简单的方式 没有排序和查询
     * 不对外开放LocalData对象了
     * @param name 对应的服务器表名
     * @param conditions 条件 二维数组 例如: String where = {{"companyname":"企业名"},{"companyid","1"}}  字符串型
     * @param sorts 排序 例如: sor1 desc, sort2, sort3 desc
     * @param pagesize 分页
     * @param pageindex 当前页
     */
    private static List<LocalData> findAll(String name, String[][] conditions, String sorts, Integer pagesize, Integer pageindex){
        check();

        //分页
        String limit = "";
        Integer firstResult, maxResult;
        if(pagesize==null||pageindex==null){

        }else{
            firstResult = (pageindex) * pagesize;
            limit = "LIMIT "+firstResult+","+pagesize;
        }

        //排序
        if(!StringUtils.isEmpty(sorts)){
            sorts = " ORDER BY "+ sorts;
        }else{
            sorts = "";
        }

        //条件
        String whe = "";
        StringBuffer where = new StringBuffer("");
        if(conditions!=null&&conditions.length>0){
            for(int i=0;i<conditions.length;i++){
                if(i>0){
                    where.append(" AND ");
                }
                where.append("name='");
                where.append(conditions[i][0]);
                where.append("'");

                where.append(" AND ");

                where.append("value='");
                where.append(conditions[i][1]);
                where.append("'");
            }
            whe = " AND id IN (SELECT pid FROM "+ SUB_TABLE_NAME +" WHERE "+ where.toString() +") ";
        }

        String sql= "SELECT * FROM "+TABLE_NAME+" WHERE name = '"+ name +"'"+ whe + sorts +" "+limit;

        Log.e(TAG,sql);

        List<LocalData> _list = new ArrayList<>();
        Cursor cursor = db.rawQuery(sql,null);
        if(cursor==null){
            return _list;
        }else{
            while (cursor.moveToNext()){
                LocalData data = cursor2model(cursor);
                _list.add(data);
            }
        }
        return _list;
    }


    /**
     * 内部类 数据库对象转换成model
     * @param cursor
     */
    private static LocalData cursor2model(Cursor cursor) {
        LocalData data = new LocalData();
        data.setId(cursor.getString(cursor.getColumnIndex("id")));
        data.setName(cursor.getString(cursor.getColumnIndex("name")));
        data.setData(cursor.getString(cursor.getColumnIndex("data")));
        data.setSort1(cursor.getString(cursor.getColumnIndex("sort1")));
        data.setSort2(cursor.getString(cursor.getColumnIndex("sort2")));
        data.setSort3(cursor.getString(cursor.getColumnIndex("sort3")));
        return data;
    }

    /**
     * 按照主键删除数据 一条
     * @param id 主键
     * @param name 表名
     */
    public static void delete(String id, String name){
        check();
        db.delete(TABLE_NAME,"id=? and name=?", new String[]{id, name});
    }

    /**
     * 按照表名删除数据
     * @param name
     */
    public static void deleteAllByName(String name){
        check();
        db.delete(TABLE_NAME,"name=?", new String[]{name});
    }

    /**
     * 删除表格 清谨慎使用 会清空所有本地数据
     */
    public static void deleteTable(){
        openDataBase();
        db.execSQL("drop table if exists " + TABLE_NAME);
        db.execSQL("drop table if exists " + SUB_TABLE_NAME);
        Log.e(TAG,"delete table success");
    }

    /**
     * 获取数据库的路径
     * @return
     */
    public String getDbPath(){
        return db.getPath();
    }




}
